package org.fujene.memman.backup;

import java.io.File;
import java.util.Date;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.fujene.memcon.ReplicateIndexMemory;

public class MemoryBackupService{
	private int interval;
	private ReplicateIndexMemory manager;
	private ConcurrentSkipListMap<Long, SnapShotStructure> backupList;
	private ExecutorService daemonSrv;
	private Thread daemon;

	public MemoryBackupService(int interval, ReplicateIndexMemory manager){
		this.interval = interval;
		this.manager = manager;
		this.backupList = new ConcurrentSkipListMap<Long, SnapShotStructure>();
		if(interval == 0) return;
		this.daemonSrv = Executors.newSingleThreadExecutor();
		this.daemon = new Thread(new SnapShotDaemon());
		this.daemon.setDaemon(true);
		this.daemonSrv.execute(daemon);
	}

	public void pickBackupData(){
		File thisDir = new File(".");
		File[] directories = thisDir.listFiles();

		for(File file: directories){
			if(file.isDirectory() && file.toString().startsWith("backup_"))
				backupList.put(Long.parseLong(file.toString().substring("backup_".length())),
						new SnapShotStructure(file.toString()));
		}
	}

	public void showList(){
		int index = 0;

		for(Entry<Long, SnapShotStructure> entries: backupList.entrySet())
			System.out.println(String.format("%5d", (index++)) + " Date: "
					+ new Date(entries.getKey()).toString() + " ID: " + entries.getKey()
					+ (entries.getValue().isToFile() ? (" -> File") : ""));
	}

	public void toFileLatest(){
		String dirname = "backup_" + backupList.lastEntry().getKey().toString() + "/";
		backupList.lastEntry().getValue().setBackupToDisk(dirname);
		manager.doBackupToFile(backupList.lastEntry().getValue());
	}

	public void fromFileLatest(){
		for(Entry<Long, SnapShotStructure> latestItem: backupList.descendingMap().entrySet()){
			if(latestItem.getValue().isToFile()){
				try{
					manager.doRevertFromFile(latestItem.getKey().longValue());
				}catch(Exception e){
					e.printStackTrace();
				}
				break;
			}
		}
	}

	public void fromFileSpecified(long ID){
		SnapShotStructure item = backupList.get(Long.valueOf(ID));
		if(item != null){
			try{
				manager.doRevertFromFile(Long.valueOf(ID));
			}catch(Exception e){
				e.printStackTrace();
			}
		}
	}

	public void stop(){
		this.daemonSrv.shutdown();
		try{
			if(!this.daemonSrv.awaitTermination(5, TimeUnit.SECONDS)){
				this.daemonSrv.shutdownNow();
			}
		}catch(InterruptedException e){
			this.daemonSrv.shutdownNow();
		}
	}

	public long addSnapshot(){
		SnapShotStructure structure = manager.copySnapshotData();
		backupList.put(Long.valueOf(structure.getID()), structure);

		System.out.println("Added " + structure.getID() + " Entries: " + backupList.size());
		return structure.getID();
	}

	public void sync(){
		this.daemon.interrupt();
	}
	
	public long latestBackupIndex() {
		return backupList.lastKey().longValue();
	}
	
	private class SnapShotDaemon implements Runnable{
		@Override
		public void run(){
			while(true){
				try{
					TimeUnit.MINUTES.sleep(interval);
				}catch(InterruptedException ignored){
					break;
				}
				SnapShotStructure structure = manager.copySnapshotData();
				backupList.put(Long.valueOf(structure.getID()), structure);
			}
		}
	}
}
